home *** CD-ROM | disk | FTP | other *** search
/ Programming an RTS Game with Direct3D / Programming an RTS Game with Direct3D.iso / Examples / Chapter 14 / Example 14.1 / skinnedMesh.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-07-17  |  10.3 KB  |  359 lines

  1. #include "skinnedMesh.h"
  2.  
  3. class BONE_HIERARCHY: public ID3DXAllocateHierarchy
  4. {
  5.     public:
  6.         STDMETHOD(CreateFrame)(THIS_ LPCSTR Name, LPD3DXFRAME *ppNewFrame);
  7.         STDMETHOD(CreateMeshContainer)(THIS_ LPCTSTR Name, CONST D3DXMESHDATA * pMeshData, CONST D3DXMATERIAL * pMaterials, CONST D3DXEFFECTINSTANCE * pEffectInstances, DWORD NumMaterials, CONST DWORD * pAdjacency, LPD3DXSKININFO pSkinInfo, LPD3DXMESHCONTAINER * ppNewMeshContainer);
  8.         STDMETHOD(DestroyFrame)(THIS_ LPD3DXFRAME pFrameToFree);
  9.         STDMETHOD(DestroyMeshContainer)(THIS_ LPD3DXMESHCONTAINER pMeshContainerBase);
  10. };
  11.  
  12. HRESULT BONE_HIERARCHY::CreateFrame(LPCSTR Name, LPD3DXFRAME *ppNewFrame)
  13. {
  14.     BONE *newBone = new BONE;
  15.     memset(newBone, 0, sizeof(BONE));
  16.  
  17.     //Copy name
  18.     if(Name != NULL)
  19.     {
  20.         newBone->Name = new char[strlen(Name)+1];
  21.         strcpy(newBone->Name, Name);
  22.     }
  23.  
  24.     //Set the transformation matrices
  25.     D3DXMatrixIdentity(&newBone->TransformationMatrix);
  26.     D3DXMatrixIdentity(&newBone->CombinedTransformationMatrix);
  27.  
  28.     //Return the new bone...
  29.     *ppNewFrame = (D3DXFRAME*)newBone;
  30.  
  31.     return S_OK;
  32. }
  33.  
  34. HRESULT BONE_HIERARCHY::CreateMeshContainer(LPCSTR Name,
  35.                                             CONST D3DXMESHDATA *pMeshData,
  36.                                             CONST D3DXMATERIAL *pMaterials,
  37.                                             CONST D3DXEFFECTINSTANCE *pEffectInstances,
  38.                                             DWORD NumMaterials,
  39.                                             CONST DWORD *pAdjacency,
  40.                                             LPD3DXSKININFO pSkinInfo,
  41.                                             LPD3DXMESHCONTAINER *ppNewMeshContainer)
  42. {
  43.     //Create new Bone Mesh
  44.     BONEMESH *boneMesh = new BONEMESH;
  45.     memset(boneMesh, 0, sizeof(BONEMESH));
  46.  
  47.     //Get mesh data
  48.     boneMesh->OriginalMesh = pMeshData->pMesh;
  49.     boneMesh->MeshData.pMesh = pMeshData->pMesh;
  50.     boneMesh->MeshData.Type = pMeshData->Type;
  51.     pMeshData->pMesh->AddRef();        //Add Reference so that the mesh isnt deallocated
  52.     IDirect3DDevice9 *m_pDevice = NULL;    
  53.     pMeshData->pMesh->GetDevice(&m_pDevice);    //Get m_pDevice ptr from mesh
  54.  
  55.     //Copy materials and load textures (just like with a static mesh)
  56.     for(int i=0;i<NumMaterials;i++)
  57.     {
  58.         D3DXMATERIAL mtrl;
  59.         memcpy(&mtrl, &pMaterials[i], sizeof(D3DXMATERIAL));
  60.         boneMesh->materials.push_back(mtrl.MatD3D);
  61.  
  62.         char textureFname[200];
  63.         strcpy(textureFname, "units/");
  64.         strcat(textureFname, mtrl.pTextureFilename);
  65.  
  66.         //Load texture
  67.         IDirect3DTexture9* newTexture = NULL;
  68.         D3DXCreateTextureFromFile(m_pDevice, textureFname, &newTexture);
  69.         boneMesh->textures.push_back(newTexture);
  70.     }
  71.  
  72.     if(pSkinInfo != NULL)
  73.     {
  74.         //Get Skin Info
  75.         boneMesh->pSkinInfo = pSkinInfo;
  76.         pSkinInfo->AddRef();    //Add reference so that the SkinInfo isnt deallocated
  77.  
  78.         //Clone mesh and store in boneMesh->MeshData.pMesh
  79.         pMeshData->pMesh->CloneMeshFVF(D3DXMESH_MANAGED, pMeshData->pMesh->GetFVF(), 
  80.                                        m_pDevice, &boneMesh->MeshData.pMesh);
  81.         
  82.         //Get Attribute Table
  83.         boneMesh->MeshData.pMesh->GetAttributeTable(NULL, &boneMesh->NumAttributeGroups);
  84.         boneMesh->attributeTable = new D3DXATTRIBUTERANGE[boneMesh->NumAttributeGroups];
  85.         boneMesh->MeshData.pMesh->GetAttributeTable(boneMesh->attributeTable, NULL);
  86.  
  87.         //Create bone offset and current matrices
  88.         int NumBones = pSkinInfo->GetNumBones();
  89.         boneMesh->boneOffsetMatrices = new D3DXMATRIX[NumBones];        
  90.         boneMesh->currentBoneMatrices = new D3DXMATRIX[NumBones];
  91.  
  92.         //Get bone offset matrices
  93.         for(int i=0;i < NumBones;i++)
  94.             boneMesh->boneOffsetMatrices[i] = *(boneMesh->pSkinInfo->GetBoneOffsetMatrix(i));
  95.     }
  96.  
  97.     //Set ppNewMeshContainer to the newly created boneMesh container
  98.     *ppNewMeshContainer = boneMesh;
  99.  
  100.     return S_OK;
  101. }
  102.  
  103. HRESULT BONE_HIERARCHY::DestroyFrame(LPD3DXFRAME pFrameToFree) 
  104. {
  105.     if(pFrameToFree)
  106.     {
  107.         //Free name
  108.         if(pFrameToFree->Name != NULL)
  109.             delete [] pFrameToFree->Name;
  110.  
  111.         //Free bone
  112.         delete pFrameToFree;
  113.     }
  114.     pFrameToFree = NULL;
  115.  
  116.     return S_OK; 
  117. }
  118.  
  119. HRESULT BONE_HIERARCHY::DestroyMeshContainer(LPD3DXMESHCONTAINER pMeshContainerBase)
  120. {
  121.     BONEMESH *boneMesh = (BONEMESH*)pMeshContainerBase;
  122.  
  123.     //Release textures
  124.     for(int i=0;i < boneMesh->textures.size();i++)
  125.         if(boneMesh->textures[i] != NULL)
  126.             boneMesh->textures[i]->Release();
  127.  
  128.     //Release mesh data
  129.     if(boneMesh->MeshData.pMesh)boneMesh->MeshData.pMesh->Release();
  130.     if(boneMesh->pSkinInfo)boneMesh->pSkinInfo->Release();
  131.     if(boneMesh->OriginalMesh)boneMesh->OriginalMesh->Release();
  132.     delete boneMesh;
  133.  
  134.     return S_OK;
  135. }
  136.  
  137.  
  138. //////////////////////////////////////////////////////////////////////////////////////////////////
  139. //                                    SKINNED MESH                                                //
  140. //////////////////////////////////////////////////////////////////////////////////////////////////
  141.  
  142. struct VERTEX{
  143.     VERTEX();
  144.     VERTEX(D3DXVECTOR3 pos, D3DCOLOR col){position = pos; color = col;}
  145.     D3DXVECTOR3 position;
  146.     D3DCOLOR color;
  147.     static const DWORD FVF;
  148. };
  149.  
  150. const DWORD VERTEX::FVF = D3DFVF_XYZ | D3DFVF_DIFFUSE;
  151.  
  152. SKINNEDMESH::SKINNEDMESH()
  153. {
  154.     m_pRootBone = NULL;
  155.     m_pAnimControl = NULL;
  156. }
  157.  
  158. SKINNEDMESH::~SKINNEDMESH()
  159. {
  160.     BONE_HIERARCHY boneHierarchy;
  161.     boneHierarchy.DestroyFrame(m_pRootBone);
  162.     if(m_pAnimControl)m_pAnimControl->Release();
  163. }
  164.  
  165. void SKINNEDMESH::Load(char fileName[], IDirect3DDevice9 *Dev)
  166. {
  167.     m_pDevice = Dev;
  168.     BONE_HIERARCHY boneHierarchy;
  169.  
  170.     D3DXLoadMeshHierarchyFromX(fileName, D3DXMESH_MANAGED, 
  171.                                m_pDevice, &boneHierarchy,
  172.                                NULL, &m_pRootBone, &m_pAnimControl);
  173.  
  174.     SetupBoneMatrixPointers((BONE*)m_pRootBone);
  175. }
  176.  
  177. void SKINNEDMESH::UpdateMatrices(BONE* bone, D3DXMATRIX *parentMatrix)
  178. {
  179.     if(bone == NULL)return;
  180.  
  181.     D3DXMatrixMultiply(&bone->CombinedTransformationMatrix,
  182.                        &bone->TransformationMatrix,
  183.                        parentMatrix);
  184.  
  185.     if(bone->pFrameSibling)UpdateMatrices((BONE*)bone->pFrameSibling, parentMatrix);
  186.     if(bone->pFrameFirstChild)UpdateMatrices((BONE*)bone->pFrameFirstChild, &bone->CombinedTransformationMatrix);
  187. }
  188.  
  189. void SKINNEDMESH::Render(BONE *bone)
  190. {
  191.     if(bone == NULL)bone = (BONE*)m_pRootBone;
  192.  
  193.     //If there is a mesh to render...
  194.     if(bone->pMeshContainer != NULL)
  195.     {
  196.         BONEMESH *boneMesh = (BONEMESH*)bone->pMeshContainer;
  197.  
  198.         if (boneMesh->pSkinInfo != NULL)
  199.         {        
  200.             // set up bone transforms
  201.             int numBones = boneMesh->pSkinInfo->GetNumBones();
  202.             for(int i=0;i < numBones;i++)
  203.                 D3DXMatrixMultiply(&boneMesh->currentBoneMatrices[i],
  204.                                    &boneMesh->boneOffsetMatrices[i], 
  205.                                    boneMesh->boneMatrixPtrs[i]);
  206.  
  207.             //Update the skinned mesh
  208.             BYTE *src = NULL, *dest = NULL;
  209.             boneMesh->OriginalMesh->LockVertexBuffer(D3DLOCK_READONLY, (VOID**)&src);
  210.             boneMesh->MeshData.pMesh->LockVertexBuffer(0, (VOID**)&dest);
  211.  
  212.             boneMesh->pSkinInfo->UpdateSkinnedMesh(boneMesh->currentBoneMatrices, NULL, src, dest);
  213.  
  214.             boneMesh->MeshData.pMesh->UnlockVertexBuffer();
  215.             boneMesh->OriginalMesh->UnlockVertexBuffer();
  216.  
  217.             //Render the mesh
  218.             for(int i=0;i < boneMesh->NumAttributeGroups;i++)
  219.             {
  220.                 int mtrlIndex = boneMesh->attributeTable[i].AttribId;
  221.                 m_pDevice->SetMaterial(&(boneMesh->materials[mtrlIndex]));
  222.                 m_pDevice->SetTexture(0, boneMesh->textures[mtrlIndex]);
  223.                 boneMesh->MeshData.pMesh->DrawSubset(mtrlIndex);
  224.             }
  225.         }
  226.     }
  227.  
  228.     if(bone->pFrameSibling != NULL)Render((BONE*)bone->pFrameSibling);
  229.     if(bone->pFrameFirstChild != NULL)Render((BONE*)bone->pFrameFirstChild);
  230. }
  231.  
  232. ID3DXMesh* SKINNEDMESH::GetCurrentMesh(BONE *bone)
  233. {
  234.     if(bone == NULL)
  235.         bone = (BONE*)m_pRootBone;
  236.  
  237.     if(bone->pMeshContainer != NULL)
  238.         return bone->pMeshContainer->MeshData.pMesh;
  239.  
  240.     ID3DXMesh* mesh = NULL;
  241.  
  242.     if(bone->pFrameSibling != NULL)mesh = GetCurrentMesh((BONE*)bone->pFrameSibling);
  243.     if(mesh == NULL && bone->pFrameFirstChild != NULL)mesh = GetCurrentMesh((BONE*)bone->pFrameFirstChild);
  244.  
  245.     return mesh;
  246. }
  247.  
  248. void SKINNEDMESH::SetupBoneMatrixPointers(BONE *bone)
  249. {
  250.     if(bone->pMeshContainer != NULL)
  251.     {
  252.         BONEMESH *boneMesh = (BONEMESH*)bone->pMeshContainer;
  253.  
  254.         if(boneMesh->pSkinInfo != NULL)
  255.         {
  256.             int NumBones = boneMesh->pSkinInfo->GetNumBones();
  257.             boneMesh->boneMatrixPtrs = new D3DXMATRIX*[NumBones];
  258.  
  259.             for(int i=0;i < NumBones;i++)
  260.             {
  261.                 BONE *b = (BONE*)D3DXFrameFind(m_pRootBone, boneMesh->pSkinInfo->GetBoneName(i));
  262.                 if(b != NULL)boneMesh->boneMatrixPtrs[i] = &b->CombinedTransformationMatrix;
  263.                 else boneMesh->boneMatrixPtrs[i] = NULL;
  264.             }
  265.         }
  266.     }
  267.  
  268.     if(bone->pFrameSibling != NULL)SetupBoneMatrixPointers((BONE*)bone->pFrameSibling);
  269.     if(bone->pFrameFirstChild != NULL)SetupBoneMatrixPointers((BONE*)bone->pFrameFirstChild);
  270. }
  271.  
  272. BONE* SKINNEDMESH::FindBone(char name[])
  273. {
  274.     return (BONE*) D3DXFrameFind(m_pRootBone, name);
  275. }
  276.  
  277. void SKINNEDMESH::SetPose(D3DXMATRIX world, ID3DXAnimationController* animControl, float time)
  278. {
  279.     if(animControl != NULL)
  280.         animControl->AdvanceTime(time, NULL);
  281.  
  282.     UpdateMatrices((BONE*)m_pRootBone, &world);
  283. }
  284.  
  285. int SKINNEDMESH::SetAnimation(char name[])
  286. {
  287.     ID3DXAnimationSet *anim = NULL;
  288.  
  289.     for(int i=0;i<m_pAnimControl->GetMaxNumAnimationSets();i++)
  290.     {
  291.         anim = NULL;
  292.         m_pAnimControl->GetAnimationSet(i, &anim);
  293.  
  294.         if(anim != NULL)
  295.         {
  296.             if(strcmp(name, anim->GetName()) == 0)
  297.             {
  298.                 m_pAnimControl->SetTrackAnimationSet(0, anim);
  299.                 anim->Release();
  300.                 return i;
  301.             }
  302.             anim->Release();
  303.         }
  304.     }
  305.  
  306.     return -1;
  307. }
  308.  
  309. void SKINNEDMESH::SetAnimation(int index)
  310. {
  311.     ID3DXAnimationSet *anim = NULL;
  312.     m_pAnimControl->GetAnimationSet(index, &anim);
  313.     if(anim != NULL)m_pAnimControl->SetTrackAnimationSet(0, anim);
  314.     anim->Release();
  315. }
  316.  
  317. float SKINNEDMESH::GetAnimationDuration(int index)
  318. {
  319.     float duration = 0.0f;
  320.     ID3DXAnimationSet *anim = NULL;
  321.     m_pAnimControl->GetAnimationSet(index, &anim);
  322.     if(anim != NULL)duration = anim->GetPeriod();
  323.     anim->Release();
  324.  
  325.     return duration;
  326. }
  327.  
  328. std::vector<std::string> SKINNEDMESH::GetAnimations()
  329. {
  330.     ID3DXAnimationSet *anim = NULL;
  331.     std::vector<std::string> animations;
  332.  
  333.     for(int i=0;i<m_pAnimControl->GetMaxNumAnimationSets();i++)
  334.     {
  335.         anim = NULL;
  336.         m_pAnimControl->GetAnimationSet(i, &anim);
  337.  
  338.         if(anim != NULL)
  339.         {
  340.             animations.push_back(anim->GetName());
  341.             anim->Release();
  342.         }
  343.     }
  344.  
  345.     return animations;
  346. }
  347.  
  348. ID3DXAnimationController* SKINNEDMESH::GetAnimationControl()
  349. {
  350.     ID3DXAnimationController* newAnimController = NULL;
  351.  
  352.     m_pAnimControl->CloneAnimationController(m_pAnimControl->GetMaxNumAnimationOutputs(),
  353.                                              m_pAnimControl->GetMaxNumAnimationSets(),
  354.                                              m_pAnimControl->GetMaxNumTracks(), 
  355.                                              m_pAnimControl->GetMaxNumEvents(),
  356.                                              &newAnimController);
  357.                                             
  358.     return newAnimController;
  359. }